package com.bruce.tool.orm.mybatis.generator.plugin;

import com.bruce.tool.orm.mybatis.core.util.ColumnUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;

import java.util.List;

/**
 * 注解方式:表-->实体类反向生成工具
 * 功能 :
 * 1.增加字段注释
 * 2.增加字段注解
 * 3.增加表字段枚举类
 * 4.增加序列化标识和接口
 *
 * @author : Bruce(刘正航) 10:22 2019-05-11
 */
public class AnnotationDomainPlugin extends PluginAdapter {

    private boolean suppressAllComments = false;

    /**
     * 包引入
     **/
    private static final String IMPORT_ID = "com.bruce.tool.orm.mybatis.core.annotation.Id";
    private final List<String> imports = Lists.newArrayList(
            "lombok.Data",
            "com.bruce.tool.orm.mybatis.core.annotation.Table",
            "com.bruce.tool.orm.mybatis.core.annotation.Column"
    );

    /**
     * 注释
     **/
    private static final String ANNOTATION_ID = "@Id";
    private static final String ANNOTATION_COLUMN = "@Column";
    private static final String ANNOTATION_TABLE = "@Table";
    private final List<String> lombokAnnotations = Lists.newArrayList("@Data");

    private static final String FIELD = "field";
    private static final String COLUMN = "column";

    @Override
    public boolean validate(final List<String> list) {
        String suppress = this.context.getProperty("suppressAllComments");
        if ((Boolean.TRUE.toString().equals(suppress) || Boolean.FALSE.toString().equals(suppress))) {
            suppressAllComments = Boolean.parseBoolean(suppress);
        }
        return true;
    }

    /**
     * 生成实体
     **/
    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        // 清空所有方法(getter/setter方法)
        topLevelClass.getMethods().clear();
        for (String annotation : lombokAnnotations) {
            topLevelClass.addAnnotation(annotation);
        }
        for (String needImport : imports) {
            topLevelClass.addImportedType(needImport);
        }

        topLevelClass.addAnnotation(ANNOTATION_TABLE + "(\"" + introspectedTable.getFullyQualifiedTableNameAtRuntime() + "\")");

        if (introspectedTable.hasPrimaryKeyColumns()) {
            topLevelClass.addImportedType(IMPORT_ID);
        }

        // 添加字段枚举类
        addFieldsEnum(topLevelClass, introspectedTable);
        return true;
    }

    /**
     * 添加字段枚举类
     **/
    private void addFieldsEnum(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        InnerEnum innerEnum = new InnerEnum(new FullyQualifiedJavaType("Attribute"));
        innerEnum.setVisibility(JavaVisibility.PUBLIC);
        innerEnum.getJavaDocLines().clear();

        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            int index = introspectedTable.getAllColumns().indexOf(introspectedColumn);
            if (index == 0) {
                innerEnum.addEnumConstant("//");
            }
            String enumKey = ColumnUtils.humpToUnderline(introspectedColumn.getJavaProperty()).toUpperCase();
            String fieldName = introspectedColumn.getJavaProperty();
            String columnName = introspectedColumn.getActualColumnName();
            innerEnum.addEnumConstant(enumKey + "(\"" + fieldName + "\",\"" + columnName + "\")");
        }

        addEnumField(innerEnum, FIELD);
        addEnumField(innerEnum, COLUMN);
        addEnumConstructor(innerEnum);
        addEnumGetMethod(innerEnum, FIELD);
        addEnumGetMethod(innerEnum, COLUMN);

        topLevelClass.addInnerEnum(innerEnum);
    }

    /**
     * 添加字段
     **/
    private void addEnumField(final InnerEnum innerEnum, final String field) {
        Field field1 = new Field(field, new FullyQualifiedJavaType("String"));
        field1.setVisibility(JavaVisibility.PRIVATE);
        field1.getJavaDocLines().clear();
        innerEnum.addField(field1);
    }

    /**
     * 添加get方法
     **/
    private void addEnumGetMethod(final InnerEnum innerEnum, String field) {
        Method method = new Method(field);
        method.setVisibility(JavaVisibility.PUBLIC);
        method.addBodyLine("return this." + field + ";");
        method.setReturnType(new FullyQualifiedJavaType("String"));
        innerEnum.addMethod(method);
    }

    /**
     * 添加构造函数
     **/
    private void addEnumConstructor(InnerEnum innerEnum) {
        Method method = new Method("Attribute");
        method.setConstructor(true);
        method.addParameter(new Parameter(new FullyQualifiedJavaType("String"), FIELD));
        method.addParameter(new Parameter(new FullyQualifiedJavaType("String"), COLUMN));
        method.addBodyLine("this." + FIELD + " = " + FIELD + ";");
        method.addBodyLine("this." + COLUMN + " = " + COLUMN + ";");
        innerEnum.addMethod(method);
    }

    /**
     * 生成字段
     **/
    @Override
    public boolean modelFieldGenerated(final Field field, final TopLevelClass topLevelClass, final IntrospectedColumn introspectedColumn, final IntrospectedTable introspectedTable, final ModelClassType modelClassType) {
        // 是主键
        if (introspectedColumn.isIdentity()) {
            field.addAnnotation(ANNOTATION_ID + "(\"" + introspectedColumn.getActualColumnName() + "\")");
            return true;
        }
        // 不是主键
        field.addAnnotation(ANNOTATION_COLUMN + "(\"" + introspectedColumn.getActualColumnName() + "\")");
        return true;
    }

}
